/*
 * TemplateManager.java
 *
 * Created on 06.02.2009, 23:37:36
 */

package de.blitzcoder.collide.templatemanager;

import de.blitzcoder.collide.Interface;
import de.blitzcoder.collide.gui.CodeDocument;
import de.blitzcoder.collide.gui.Document;
import de.blitzcoder.collide.gui.IDEDialog;
import de.blitzcoder.collide.gui.textarea.CollIDETextArea;
import de.blitzcoder.collide.util.KeyStrokeUtil;
import de.blitzcoder.collide.util.Log;
import groovy.lang.GroovyShell;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
import javax.swing.DefaultListModel;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.gjt.sp.jedit.buffer.BufferListener;
import org.gjt.sp.jedit.buffer.JEditBuffer;

/**
 *
 * @author blitzcoder
 */
public class TemplateManager extends IDEDialog implements ListSelectionListener, CaretListener {


    // GUI Stuff
    private CollIDETextArea textArea;
    private DefaultListModel templateListModel;

    // The template which is currently selected
    private Template currentTemplate = null;

    // If this is true, selection events are ignored
    private boolean selectionLocked = false;

    // If this is true, update events are ignored
    private boolean updateLocked = false;

    // All availabe Key names and their codes
    private static final int[] keyCodes;
    private static final String[] keyNames;

    // Fill the key Arrays
    static {
        try {
            Field[] fields = KeyEvent.class.getDeclaredFields();
            int size = 0;
            for (Field f:fields) {
                if (f.getName().startsWith("VK_"))
                    size++;
            }
            keyCodes = new int[size];
            keyNames = new String[size];
            int i = 0;
            for (Field f:fields) {
                if (f.getName().startsWith("VK_")) {
                    keyCodes[i] = f.getInt(f);
                    keyNames[i] = f.getName().substring(3); // Cut "VK_"
                    i++;
                }
            }
        } catch(Exception ex) {
            throw new Error(ex);
        }
        
    }

    /** Creates new form TemplateManager */
    public TemplateManager() {
        super(Interface.get());
        initComponents();

        setMinimumSize(new Dimension(600,400));

        textArea = new CollIDETextArea();
        textArea.setFileExtension("bmx", "blitzmax.xml");
        textArea.setMinimumSize(new Dimension(0,50));
        codePanel.add(textArea);

        // Template should be updated if somebody types
        textArea.getBuffer().addBufferListener(new BufferListener() {
            public void foldLevelChanged(JEditBuffer arg0, int arg1, int arg2) {}
            public void contentInserted(JEditBuffer arg0, int arg1, int arg2, int arg3, int arg4) {
                updateTemplate();
            }
            public void contentRemoved(JEditBuffer arg0, int arg1, int arg2, int arg3, int arg4) {
                updateTemplate();
            }
            public void preContentInserted(JEditBuffer arg0, int arg1, int arg2, int arg3, int arg4) {}
            public void preContentRemoved(JEditBuffer arg0, int arg1, int arg2, int arg3, int arg4) {}
            public void transactionComplete(JEditBuffer arg0) {}
            public void foldHandlerChanged(JEditBuffer arg0) {}
            public void bufferLoaded(JEditBuffer arg0) {}
        });

        // Create TemplateListModel
        templateListModel = new DefaultListModel();
        templateList.setModel(templateListModel);
        templateList.addListSelectionListener(this);

        // Fill the KeyComboBox
        keyComboBox.removeAllItems();
        for (String name:keyNames)
            keyComboBox.addItem(name);

        // To update the actual template if somebody types
        nameTextField.addCaretListener(this);
        shortcutTextField.addCaretListener(this);

        // Disable all components. They get enabled if a template is selected
        setComponentsEnabled(false);

        loadTemplates();

        setVisible(true);

    }

    private void loadTemplates() {
        fillTemplateList();
    }

    /*
     * Interface ListSelectionListener
     */
    @Override
    public void valueChanged(ListSelectionEvent e) {

        if (!selectionLocked)
            fillTemplate();
    }

    private void fillTemplate() {

        updateLocked = true;

        int selection = templateList.getSelectedIndex();

        if (selection != -1) {
            
            Template t = Template.getList().get(selection);

            currentTemplate = t;

            // Set the values
            nameTextField.setText(t.getName());
            shortcutTextField.setText(t.getShortcutText());
            textArea.setText(t.getCode());

            KeyStroke s = t.getShortcut();
            altCheckBox.setSelected(KeyStrokeUtil.isAltDown(s));
            ctrlCheckBox.setSelected(KeyStrokeUtil.isCtrlDown(s));

            for (int i=0;i<keyCodes.length;i++)
                if (keyCodes[i] == s.getKeyCode()) {
                    keyComboBox.setSelectedIndex(i);
                    break;
                }

            // Fill Variables
            variableComboBox.removeAllItems();
            ListIterator<TemplateVariable> it = t.getVariables().listIterator();
            while (it.hasNext()) {
                TemplateVariable var = it.next();
                variableComboBox.addItem(var.getRealName()+" ("+var.getVarName()+")");
            }
            
            setComponentsEnabled(true);

        }

        updateLocked = false;
        
    }

    private void fillTemplateList() {

        int selection = templateList.getSelectedIndex();
        templateListModel.clear();

        LinkedList<Template> list = Template.getList();
        ListIterator<Template> it = list.listIterator();
        while (it.hasNext()) {
            Template t = it.next();
            templateListModel.addElement(t.getName());
        }

        if (list.size() != 0) {
            if (selection == -1)
                templateList.setSelectedIndex(0);
            else
                if (selection >= list.size())
                    templateList.setSelectedIndex(0);
                else
                    templateList.setSelectedIndex(selection);
        }
        
        setComponentsEnabled(list.size() != 0);

    }

    private void setComponentsEnabled(boolean b) {
        updateLocked = true;
        nameTextField.setEnabled(b);
        shortcutTextField.setEnabled(b);
        altCheckBox.setEnabled(b);
        ctrlCheckBox.setEnabled(b);
        keyComboBox.setEnabled(b);
        variableComboBox.setEnabled(b);
        addVariable.setEnabled(b);
        removeVariable.setEnabled(b);
        textArea.setEnabled(b);
        removeButton.setEnabled(b);
        updateLocked = false;
    }

    private void updateTemplate() {

        if (updateLocked)
            return;

        if (currentTemplate != null) {

            currentTemplate.setName(nameTextField.getText());
            currentTemplate.setShortcutText(shortcutTextField.getText());
            currentTemplate.setCode(textArea.getText());

            KeyStroke s = KeyStrokeUtil.getKeyStroke(ctrlCheckBox.isSelected(), altCheckBox.isSelected(), keyCodes[keyComboBox.getSelectedIndex()]);
            currentTemplate.setShortcut(s);

            selectionLocked = true;
            fillTemplateList();
            selectionLocked = false;

        }

    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        closeButton = new javax.swing.JButton();
        jScrollPane1 = new javax.swing.JScrollPane();
        templateList = new javax.swing.JList();
        jLabel1 = new javax.swing.JLabel();
        nameTextField = new javax.swing.JTextField();
        jLabel2 = new javax.swing.JLabel();
        shortcutTextField = new javax.swing.JTextField();
        ctrlCheckBox = new javax.swing.JCheckBox();
        altCheckBox = new javax.swing.JCheckBox();
        keyComboBox = new javax.swing.JComboBox();
        codePanel = new javax.swing.JPanel();
        jLabel3 = new javax.swing.JLabel();
        addButton = new javax.swing.JButton();
        removeButton = new javax.swing.JButton();
        variableComboBox = new javax.swing.JComboBox();
        addVariable = new javax.swing.JButton();
        removeVariable = new javax.swing.JButton();
        jLabel4 = new javax.swing.JLabel();
        aboutButton = new javax.swing.JButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        setTitle("TemplateManager");
        setModal(true);
        getContentPane().setLayout(new java.awt.GridBagLayout());

        closeButton.setText("Schließen");
        closeButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                closeButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 6;
        gridBagConstraints.gridwidth = 8;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        getContentPane().add(closeButton, gridBagConstraints);

        jScrollPane1.setMinimumSize(new java.awt.Dimension(180, 22));

        templateList.setModel(new javax.swing.AbstractListModel() {
            String[] strings = { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };
            public int getSize() { return strings.length; }
            public Object getElementAt(int i) { return strings[i]; }
        });
        templateList.setMinimumSize(new java.awt.Dimension(200, 85));
        jScrollPane1.setViewportView(templateList);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.gridwidth = 2;
        gridBagConstraints.gridheight = 6;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weighty = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        getContentPane().add(jScrollPane1, gridBagConstraints);

        jLabel1.setText("Name:");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 2;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        getContentPane().add(jLabel1, gridBagConstraints);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 3;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.gridwidth = 5;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        getContentPane().add(nameTextField, gridBagConstraints);

        jLabel2.setText("Shortcut-Text:");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 2;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        getContentPane().add(jLabel2, gridBagConstraints);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 3;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.gridwidth = 5;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        getContentPane().add(shortcutTextField, gridBagConstraints);

        ctrlCheckBox.setText("Strg");
        ctrlCheckBox.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                ctrlCheckBoxStateChanged(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 3;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        getContentPane().add(ctrlCheckBox, gridBagConstraints);

        altCheckBox.setText("Alt");
        altCheckBox.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                altCheckBoxStateChanged(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 4;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        getContentPane().add(altCheckBox, gridBagConstraints);

        keyComboBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
        keyComboBox.addItemListener(new java.awt.event.ItemListener() {
            public void itemStateChanged(java.awt.event.ItemEvent evt) {
                keyComboBoxItemStateChanged(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 5;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.gridwidth = 3;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        getContentPane().add(keyComboBox, gridBagConstraints);

        codePanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Code"));
        codePanel.setLayout(new java.awt.GridLayout(1, 0));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 2;
        gridBagConstraints.gridy = 4;
        gridBagConstraints.gridwidth = 6;
        gridBagConstraints.gridheight = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        getContentPane().add(codePanel, gridBagConstraints);

        jLabel3.setText("Tastenkombination:");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 2;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        getContentPane().add(jLabel3, gridBagConstraints);

        addButton.setText("+");
        addButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                addButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 6;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
        gridBagConstraints.insets = new java.awt.Insets(2, 2, 2, 2);
        getContentPane().add(addButton, gridBagConstraints);

        removeButton.setText("-");
        removeButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                removeButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 6;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.insets = new java.awt.Insets(2, 2, 2, 2);
        getContentPane().add(removeButton, gridBagConstraints);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 3;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.gridwidth = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        getContentPane().add(variableComboBox, gridBagConstraints);

        addVariable.setText("+");
        addVariable.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                addVariableActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 5;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        getContentPane().add(addVariable, gridBagConstraints);

        removeVariable.setText("-");
        removeVariable.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                removeVariableActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 6;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        getContentPane().add(removeVariable, gridBagConstraints);

        jLabel4.setText("Variablen:");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 2;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        getContentPane().add(jLabel4, gridBagConstraints);

        aboutButton.setText("?");
        aboutButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                aboutButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 7;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        getContentPane().add(aboutButton, gridBagConstraints);

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void addButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addButtonActionPerformed
        new Template();
        fillTemplateList();
        templateList.setSelectedIndex(templateListModel.getSize()-1);
    }//GEN-LAST:event_addButtonActionPerformed

    private void keyComboBoxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_keyComboBoxItemStateChanged
        updateTemplate();
    }//GEN-LAST:event_keyComboBoxItemStateChanged

    private void ctrlCheckBoxStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_ctrlCheckBoxStateChanged
        updateTemplate();
    }//GEN-LAST:event_ctrlCheckBoxStateChanged

    private void altCheckBoxStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_altCheckBoxStateChanged
        updateTemplate();
    }//GEN-LAST:event_altCheckBoxStateChanged

    private void removeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeButtonActionPerformed
        int sel = templateList.getSelectedIndex();
        if (sel != -1) {
            Template.getList().remove(sel);
            fillTemplateList();
        }
    }//GEN-LAST:event_removeButtonActionPerformed

    private void closeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeButtonActionPerformed
        dispose();
    }//GEN-LAST:event_closeButtonActionPerformed

    private void addVariableActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addVariableActionPerformed
        String name = JOptionPane.showInputDialog(this,"Variablennamen eingeben");
        String real = JOptionPane.showInputDialog(this,"Beschreibung eingeben");
        TemplateVariable var = new TemplateVariable(real, name);
        currentTemplate.addVariable(var);
        fillTemplate();
    }//GEN-LAST:event_addVariableActionPerformed

    private void removeVariableActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeVariableActionPerformed
        if (variableComboBox.getItemCount() != 0) {
            currentTemplate.removeVariable(variableComboBox.getSelectedIndex());
            fillTemplate();
        }
    }//GEN-LAST:event_removeVariableActionPerformed

    private void aboutButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_aboutButtonActionPerformed
        String msg = "";
        msg+="Variablen\n";
        msg+="-----------\n";
        msg+="\n";
        msg+="Variablen werden beim einfügen eines Templates abgefragt.\n";
        msg+="Sie können benutzt werden um eine im Template mehrfach\n";
        msg+="vorkommende Stelle nur einmal Tippen zu müssen.\n";
        msg+="\n";
        msg+="Variablen müssen im Code zwischen 2 Dollarzeichen ($)\n";
        msg+="stehen. Ebenso können sie <cursor> verwenden um den Cursor\n";
        msg+="entsprechend zu platzieren.";

        JOptionPane.showMessageDialog(this, msg);
    }//GEN-LAST:event_aboutButtonActionPerformed

    @Override
    public void dispose() {
        fillTemplateMenu();
        super.dispose();
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton aboutButton;
    private javax.swing.JButton addButton;
    private javax.swing.JButton addVariable;
    private javax.swing.JCheckBox altCheckBox;
    private javax.swing.JButton closeButton;
    private javax.swing.JPanel codePanel;
    private javax.swing.JCheckBox ctrlCheckBox;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JComboBox keyComboBox;
    private javax.swing.JTextField nameTextField;
    private javax.swing.JButton removeButton;
    private javax.swing.JButton removeVariable;
    private javax.swing.JTextField shortcutTextField;
    private javax.swing.JList templateList;
    private javax.swing.JComboBox variableComboBox;
    // End of variables declaration//GEN-END:variables

    // Interface CaretListener
    // Updates the properties when typing in one of the textfield
    public void caretUpdate(CaretEvent e) {
        updateTemplate();
    }

    // Fill the Templatemanu
    public static void fillTemplateMenu() {

        JMenu menu = Interface.get().getMenu().getMenu("templates");

        menu.removeAll();

        ListIterator<Template> it = Template.getList().listIterator();
        while (it.hasNext()) {
            final Template t = it.next();

            JMenuItem item = new JMenuItem(t.getName());
            item.setAccelerator(t.getShortcut());
            
            item.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    Document doc = Interface.getDocumentManager().getCurrentDocument();
                    if (doc != null && doc instanceof CodeDocument) {
                        startTemplateInsertion(((CodeDocument)doc).getTextArea(),t);
                    }
                    
                }
            });

            menu.add(item);

        }

    }

    public static void startTemplateInsertion(CollIDETextArea textArea,Template t) {

        LinkedList<TemplateVariable> varList =  t.getVariables();
        if (varList.size() != 0)
            askForVars(t,textArea);
        else
            insertTemplate(t, null,textArea);

    }

    /*
     * Returns:
     * String[] {
     *  code,
     *  groovy
     * }
     *
     */
    private static String[] splitCodeAndGroovy(String code) {
        
        String[] lines = code.split("\n");
        code = "";
        String groovy = "";
        boolean inGroovy = false;
        for (String line:lines) {

            if (line.toLowerCase().trim().equals("endgroovy")) {
                inGroovy = false;
                continue;
            }
            if (line.toLowerCase().trim().equals("groovy")) {
                inGroovy = true;
                continue;
            }

            if (line.startsWith(">>")) {
                groovy+="\n"+line.substring(2);
            } else if (inGroovy) {
                groovy+="\n"+line;
            } else {
                code+="\n"+line;
            }

        }
        
        code = code.substring(1); // Cut the first \n
        return new String[] {code,groovy};
    }

    private static void insertTemplate(Template t,HashMap<String,String> vars,CollIDETextArea textArea) {

        String code = t.getCode();
        String[] gc = splitCodeAndGroovy(code);
        code = gc[0];

        if (gc[1].length() != 0) {
            if (vars == null)
                vars = new HashMap<String, String>();
            GroovyShell shell = new GroovyShell();
            shell.setVariable("vars", vars);
            try {
            shell.evaluate(gc[1]);
            } catch (Exception ex) {
                JOptionPane.showMessageDialog(Interface.get(),"Fehler bei Auführung des Template-Scripts:\n\n"+ex.getMessage());
                return;
            }
            vars = (HashMap<String,String>)shell.getContext().getVariable("vars");
        }

        // Put in the vars
        if (vars != null) {
            Iterator<String> it = vars.keySet().iterator();
            while (it.hasNext()) {
                String varName = it.next();
                String varCode = vars.get(varName);
                code = code.replace("$"+varName+"$", varCode);
                Log.log("Replacing $"+varName+"$ with "+varCode);
            }
        }

        // Check if the cursor position is specified
        int caret = -1;
        int cursorIndex = code.indexOf("<cursor>");
        if (cursorIndex != -1) {
            caret = textArea.getCaretPosition() + cursorIndex;
            code = code.replace("<cursor>", "");
        }

        // Set the right indention
        code = code.replace("\n", "\n"+textArea.getIndent(textArea.getCaretLine()));

        // Insert Template
        textArea.getBuffer().insert(textArea.getCaretPosition(), code);

        // Set the caret, if specified
        if (caret != -1)
            textArea.setCaretPosition(caret);

    }

    private static void askForVars(final Template t,final CollIDETextArea textArea) {
        
        final IDEDialog dialog = new IDEDialog(Interface.get(), "Template: "+t.getName());
        dialog.setLayout(new GridBagLayout());
        GridBagConstraints c = new GridBagConstraints();
        dialog.setPreferredSize(new Dimension(250,t.getVariables().size()*35+30));

        final LinkedList<TemplateVariable> list = t.getVariables();
        final JTextField[] textFields = new JTextField[list.size()];

        ListIterator<TemplateVariable> it = list.listIterator();
        int i=0;
        while (it.hasNext()) {
            TemplateVariable var = it.next();
            JLabel label = new JLabel(var.getRealName()+":");
            label.setMinimumSize(new Dimension(1,25));
            textFields[i] = new JTextField();
            textFields[i].setPreferredSize(new Dimension(1,25));

            c.gridy = i;
            c.fill = c.BOTH;
            c.insets = new Insets(3, 3, 3, 3);

            c.weightx = 0.0;
            c.gridx = 0;

            dialog.add(label,c);

            c.gridx = 1;
            c.weightx = 1.0;
            dialog.add(textFields[i],c);

            final int current = i;
            if (i == list.size()-1) {
                textFields[i].addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {

                        dialog.dispose();

                        // Build the HashMap and insert Template
                        ListIterator<TemplateVariable> l = list.listIterator();
                        int i=0;
                        HashMap<String, String> vars = new HashMap<String, String>();
                        while (l.hasNext()) {
                            vars.put(l.next().getVarName(), textFields[i].getText());
                            i++;
                        }

                        insertTemplate(t, vars, textArea);

                    }
                });
            } else {
                textFields[i].addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        textFields[current+1].requestFocus();
                    }
                });
            }

            i++;
        }

        dialog.pack();
        dialog.setVisible(true);

    }

}
